Route Offline Snapshots
Catalyst can cache SSR HTML snapshots for selected routes. After a successful online visit to an eligible SSR route, Catalyst stores the rendered HTML for that exact URL. If the same URL is opened later while the server or network is unavailable, Catalyst can serve the cached HTML and hydrate the page with cached runtime assets.
API responses and non-GET requests are not cached by route offline snapshots.
Developer API
Enable route snapshots through route config:
{
path: "/home",
component: Home,
offline: true,
}
offline: true applies to that route and its child URL subtree. Index routes are exact-match only,
so a root index route caches / without making every URL eligible. Snapshots are stored by exact
visited URL, so /home, /home?tab=a, and /home/settings are separate cached documents.
Route eligibility is matched by path. Query strings are ignored for route eligibility, but they are kept in the snapshot cache key.
Examples:
{ path: "/home", offline: true }
// eligible: /home, /home/settings, /home?tab=a
{ path: "/account", children: [{ path: "", offline: true }] }
// eligible: /account
// not eligible: /account/settings
{ path: "/", index: true, offline: true }
// eligible: /
// not every app route
Build Output
Production-style builds generate Catalyst-owned offline runtime files in build/public:
catalyst-offline-manifest.jsoncatalyst-sw.js
If the app provides public/offline.html, Catalyst copies it to build/public/offline.html and
uses it as the fallback when an eligible route has not been visited online yet.
The manifest contains:
- schema version;
- build id;
- offline route patterns and match regexes.
The build id namespaces caches by origin + buildId, so new builds naturally create a fresh cache
space while older snapshots can remain as last-known-good data until cleanup.
Web Runtime
The browser client registers /catalyst-sw.js only in production web builds, not inside native
WebViews.
The service worker:
- fetches and stores the latest offline manifest;
- uses a network-first strategy for eligible route navigations;
- stores successful
text/htmlSSR responses by exact URL; - returns an exact cached route snapshot only when the navigation fetch fails;
- caches intercepted JS, CSS, font, and image requests on demand;
- deletes old Catalyst build caches on service worker activation;
- falls back to
/offline.htmlwhen no route snapshot exists; - ignores non-GET requests.
Native Runtime
Android and iOS use native offline cache services instead of the web service worker.
Native request interception:
- refreshes the manifest while online;
- treats main-frame GET document requests under offline route subtrees as snapshot eligible;
- lets the original online WebView navigation continue normally;
- stores successful
text/htmlsnapshots by exact URL in the background; - skips background snapshot refresh when the existing snapshot is still fresh;
- sends
X-Catalyst-Offline-Snapshot-Fetch: 1on native background snapshot fetches; - serves a cached snapshot when the same URL is requested offline;
- lets API requests and non-GET requests pass through uncached;
- keeps existing
cachePatternbehavior as a global/manual native cache policy; - adds same-origin GET subresources requested by an active offline route to the native asset cache path, while still excluding API and document/data responses where native can identify them.
Use cachePattern for cross-origin/CDN assets or custom asset endpoints that native cannot safely
identify as route subresources.
Offline app launch and notification navigation first try a cached route snapshot. If no snapshot is
available, Catalyst falls back to bundled public/offline.html.
Online Recovery
Route snapshots do not replace normal online loading. When the device or browser is online again, future route reloads, retry actions, and navigations use the network first and refresh the cached snapshot after a successful response.
If the user is already viewing the bundled offline fallback page, Catalyst does not automatically reload the page on connectivity recovery. The user must retry, reload, or navigate again for the online route to load. This avoids unexpectedly replacing visible content or interrupting in-progress user state during partial connectivity.
Cached JS, CSS, font, and image assets may still be served from the asset cache while fresh or while being revalidated. API responses and non-GET requests are not served from route offline snapshots.
Data Clearing
clearWebData clears:
- WebView/browser data;
- existing Catalyst asset cache;
- route offline snapshots and cached offline manifest.
Only mark routes offline: true when their SSR HTML is public or safe to persist on the device, or
when the app guarantees clearWebData on logout and user switch.
Custom Documents
Native WebView requests include X-Catalyst-Native-WebView: 1. Catalyst uses this to expose
nativeWebView to the SSR document and to inject window.__CATALYST_NATIVE_WEBVIEW__ from the
default <Body /> component.
Apps with a custom server/document.js should pass all document props through to Catalyst's
<Body />, or explicitly pass nativeWebView, so cached native SSR snapshots keep the same native
layout/runtime behavior as online pages:
import { Head, Body } from "catalyst-core";
export default function Document(props) {
return (
<html lang={props.lang}>
<Head {...props} />
<Body {...props} />
</html>
);
}
If a custom document does not render Catalyst's <Body />, it must inject the equivalent
window.__CATALYST_NATIVE_WEBVIEW__ value itself.
Key Files
packages/catalyst-core/src/scripts/generateOfflineManifest.jspackages/catalyst-core/src/offline/registerServiceWorker.jspackages/catalyst-core/src/server/expressServer.jspackages/catalyst-core/src/native/androidProject/app/src/main/java/io/yourname/androidproject/OfflineCacheService.ktpackages/catalyst-core/src/native/iosnativeWebView/Sources/Core/Utils/OfflineCacheService.swiftpackages/catalyst-core/src/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.ktpackages/catalyst-core/src/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift
Non-Goals
- API response caching
- non-GET request caching
- pre-rendering routes that were never visited
- cross-user route snapshot reuse